﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FaceRecognition
{
    class PGM
    {
        private string _filePath;
        private string _folderPath;
        private string[] _filePaths = null;

        public string filePath
        {
            get
            {
                return _filePath;
            }
            set
            {
                _filePath = value.ToString();
            }
        }
        public string folderPath
        {
            get
            {
                return _folderPath;
            }
            set
            {
                _folderPath = value.ToString();
            }
        }
        public string[] filePaths
        {
            get
            {
                if (_filePaths != null)
                {
                    return _filePaths;
                }
                else
                {
                    Console.WriteLine("Folder " + _folderPath + " does not contains PGM files or not exists.");
                    return null;
                }
            }
            set
            {
                if (!_folderPath.Equals(""))
                {
                    if (Directory.Exists(_folderPath))
                    {
                        _filePaths = Directory.GetFiles(_folderPath, "*.pgm");
                    }
                }
            }
        }

        public PGM()
        {

        }

        public PGM(string fPath)
        {
            if (fPath.Contains(".pgm"))
            {
                _filePath = fPath;
                _folderPath = "";
            }
            else
            {
                if (fPath.Substring(fPath.Length - 1, 1).Equals("\\"))
                {
                    _folderPath = fPath;
                    if (Directory.Exists(fPath))
                    {
                        _filePaths = Directory.GetFiles(fPath, "*.pgm");
                    }
                }
                else
                {
                    _folderPath = fPath + "\\";
                    if (Directory.Exists(fPath))
                    {
                        _filePaths = Directory.GetFiles(fPath + "\\", "*.pgm");
                    }
                }

                _filePath = "";
            }
            
        }

        public static int[] ReadPGM(string fPath, out int mLength, out int mWidth, out int mColor, out string mType)
        {
            FileStream InputStream = File.OpenRead(fPath);
            BinaryReader PGMReader = new BinaryReader(InputStream);

            string mComments;
            char[] Seperators = { ' ', '\n' };
            
            byte NewLineAsciiCode = 10;
            byte DiezAsciiCode = 35;
            byte SpaceAsciiCode = 32;
            
            int[] A;
            byte[] mData;
            byte[] TempArray = new byte[1000];
            int i = 0;

            string TempS;
            byte TempByte;
            
            /* Sample PGM :
             * 
             * 
             * P2
             * # Created by ...
             * 512 512
             * 255
             * [data]
             */
            //read PGM Type P2, P5
            TempArray[0] = PGMReader.ReadByte();
            TempArray[1] = PGMReader.ReadByte();
            mType = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, 2);

            //read until new line
            while (PGMReader.ReadByte() != NewLineAsciiCode) { ;}

            //read comments if exists. Only one comment line supported!!
            
            i = 0;
            TempArray[i] = PGMReader.ReadByte();

            if (TempArray[i] == DiezAsciiCode)
            {
                TempByte = PGMReader.ReadByte();
                while (TempByte != NewLineAsciiCode)
                {
                    TempArray[i++] = TempByte;
                    TempByte = PGMReader.ReadByte();
                }
            }
            mComments = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            
            //read width
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != SpaceAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            mWidth = Convert.ToInt32(TempS);

            //read length
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != NewLineAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            mLength = Convert.ToInt32(TempS);

            //read color
            i = 0;
            TempByte = PGMReader.ReadByte();
            while (TempByte != NewLineAsciiCode)
            {
                TempArray[i++] = TempByte;
                TempByte = PGMReader.ReadByte();
            }

            TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
            mColor = Convert.ToInt32(TempS);

            //read image data
            byte[] PGMDataBuffer = new byte[mWidth * mLength];
            int k = 0;
            if (mType == "P5")
            {
                //If file is binary, read every byte
                byte[] ReadedByte = PGMReader.ReadBytes(PGMDataBuffer.Length);
                Array.Copy(ReadedByte, PGMDataBuffer, ReadedByte.Length);
            }
            else if (mType == "P2")
            {
                //If file is text based every pixel is distinguished by "space" and it has up to 3 chars(255)
                try
                {
                    TempByte = PGMReader.ReadByte();
                    while (TempByte != -1)
                    {
                        i = 0;
                        while (TempByte != NewLineAsciiCode && TempByte != SpaceAsciiCode)
                        {
                            TempArray[i++] = TempByte;
                            TempByte = PGMReader.ReadByte();
                        }

                        TempS = System.Text.ASCIIEncoding.Default.GetString(TempArray, 0, i);
                        i = 0;
                        //TempS contains, string representation of every pixel
                        PGMDataBuffer[k++] = Convert.ToByte(TempS);

                        TempByte = PGMReader.ReadByte();
                        if (TempByte == NewLineAsciiCode || TempByte == SpaceAsciiCode)
                        {
                            TempByte = PGMReader.ReadByte();
                        }
                    }
                }
                catch (Exception e)
                {
                    //Console.WriteLine(e.InnerException);
                    ;
                }
            }

            A = new int[mWidth*mLength];
            mData = PGMDataBuffer;
            
            i = 0;

            foreach(byte pp in mData) 
            {
                A[i++] = Convert.ToInt32(pp);
            }

            PGMReader.Close();
            InputStream.Close();
            return A;
        }

        public static void WritePGM(string fPath, int mLength, int mWidth, int mColor, string mType, int[] A)
        {
            FileStream OutputStream = File.Create(fPath);
            BinaryWriter PGMWriter = new BinaryWriter(OutputStream);
            byte[] mData;

            mData = new byte[mWidth * mLength];

            int i = 0;
            foreach (int k in A)
            {
                mData[i++] = Convert.ToByte(k);
            }

            string PGMInfo = mType + Convert.ToChar(10) +           
                        mWidth.ToString() + " " + mLength.ToString() + Convert.ToChar(10) +
                        mColor.ToString() + Convert.ToChar(10); 

            byte[] PGMInfoBuffer = System.Text.ASCIIEncoding.Default.GetBytes(PGMInfo);
            PGMWriter.Write(PGMInfoBuffer);
            if (mType == "P5")
            {
                //File is binary, write complete data
                PGMWriter.Write(mData);
            }
            else if (mType == "P2")
            {
                byte NewLineAsciiCode = 10;
                byte SpaceAsciiCode = 32;
                int Temp;

                for (i = 0; i < mLength * mWidth; i++)
                {
                    //File is text based, convert every byte to text representation followed by "space"
                    Temp = mData[i];
                    byte[] TempByteArray = System.Text.ASCIIEncoding.Default.GetBytes(Temp.ToString());

                    PGMWriter.Write(TempByteArray);
                    PGMWriter.Write(SpaceAsciiCode);
                    if (i % mWidth == 0)
                    {
                        PGMWriter.Write(NewLineAsciiCode);
                    }
                }
            }
            PGMWriter.Close();

        }
    }
}
